/*******************************************************************************
 * Copyright (c) 2013, 2014 EclipseSource and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    EclipseSource - initial API and implementation
 ******************************************************************************/
package org.apache.hop.ui.hopgui;

import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.vfs2.FileObject;
import org.apache.hop.core.Const;
import org.apache.hop.core.database.RunPython;
import org.apache.hop.core.vfs.HopVfs;
import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.dialog.BaseDialog;
import org.apache.hop.ui.core.gui.GuiResource;
import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.json.JSONObject;

public class Chatgpt extends Dialog {
  private static final Class<?> PKG =
      org.apache.hop.ui.core.dialog.ShowBrowserDialog.class; // For Translator

  private static final String[] WIDGETS =
      new String[] {"参考当前文件生成内容", "参考当前文件夹下生成内容", "参考系统帮助", "不参考任何文件"};
  private static final String[] GENTMPLATE =
      new String[] {
        "指标-dws-ads",
        "数据流-dws-ads",
        "数据流-dwd",
        "数据流-grafana",
        "数据流-dws",
        "数据流-ads",
        "MCP和API-Sql实现",
        "C语言实现",
        "MCP和API-python实现"
      };

  private final String dialogTitle;
  GridData gdQuest;
  GridData gdAn;
  private String user_prompt = "";
  private Text question;
  private Text answer;
  private Combo widgetCombo;
  private Combo genCombo;
  private Shell shell;
  private FileObject fileObj;
  private boolean isFile = false;
  private String hpl = "";
  private String hwf = "";

  public Chatgpt(Shell parent, String dialogTitle) {
    super(parent, SWT.NONE);
    this.dialogTitle = dialogTitle;
  }

  /**
   * 设置文件
   *
   * @param fileObj 文件对象
   */
  public void setFileObj(FileObject fileObj) {
    this.fileObj = fileObj;
    try {
      isFile = fileObj.isFile();
      if (!isFile) return;
      String filePath = fileObj.getPath().toString();
      this.user_prompt = new String(Files.readAllBytes(Paths.get(filePath)));
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public void open() {
    Shell parent = getParent();

    shell = new Shell(parent, SWT.MAX | SWT.RESIZE);
    shell.setImage(GuiResource.getInstance().getImageHopUi());
    PropsUi.setLook(shell);
    shell.setText(dialogTitle);
    createStyleControls(shell);
    BaseDialog.defaultShellHandling(shell, c -> ok(), c -> ok());
  }

  public void dispose() {
    shell.dispose();
  }

  private void ok() {
    dispose();
  }

  /** 处理生成按钮的事件 */
  private void handleSetBtn(String tools_name) {
    try {
      answer.setText("大模型思考中......");
      String dir = fileObj.getPath().toString();
      System.out.println("dir=" + dir);
      String ret = "";
      String txt = question.getText().replaceAll("\\r?\\n", " ");
      System.out.println("[bzm-chatgpt-handleSetBtn]txt=" + txt);
      // String encoded = Base64.getEncoder().encodeToString(txt.getBytes());
      switch (widgetCombo.getSelectionIndex()) {
        case 0: // "参考当前文件生成内容"
          if (isFile) {
            ret = RunPython.runFileChat(dir, txt);
          } else {
            MessageBox box = new MessageBox(shell);
            box.setMessage("请选择一个文件");
            box.open();
            ret = "请选择一个文件";
          }
          break;
        case 1: // "参考当前文件夹下的文件生成内容"
          ret = Const.llmdb_api(tools_name, new String[] {txt});
          break;
        case 2: // , "参考系统默认的帮助知识库"
          ret = RunPython.runDirChat("systemdochelp12345678", txt);
          break;
        case 3: // "不参考任何文件"
          ret = RunPython.runFileChat("", txt);
          break;
      }
      answer.setText(ret);
    } catch (Exception e) {
      answer.setText("生成失败:" + e);
    }
  }

  protected void createStyleControls(Shell parent) {
    parent.setLayout(new GridLayout(1, false));
    widgetCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
    widgetCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    // gridData.horizontalSpan = 2;
    widgetCombo.setItems(WIDGETS);
    if (isFile) widgetCombo.select(0);
    else widgetCombo.select(1);
    genCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
    genCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    genCombo.setItems(GENTMPLATE);
    genCombo.select(0);
    genCombo.addListener(
        SWT.Selection,
        new Listener() {
          @Override
          public void handleEvent(Event event) {
            handleGenCombo();
          }
        });
    SashForm sashForm = new SashForm(parent, SWT.HORIZONTAL | SWT.BORDER);
    GridData shGd = new GridData(GridData.FILL_BOTH);
    sashForm.setLayoutData(shGd);
    question = new Text(sashForm, SWT.MULTI | SWT.WRAP);
    gdQuest = new GridData(GridData.FILL_HORIZONTAL);
    // gdQuest.heightHint = 300;
    question.setLayoutData(gdQuest);
    String questr =
        "根据dwd_dev_print_list表名称生dws和ads表.\n"
            + "1. 查询维度是 型号,版本\n"
            + "2. 统计指标是(一定要加单引号,不然会变成英文) '打印成功次数,打印成功率'\n"
            + "3. 条件是 print_id is not null";
    question.setText(questr);
    // add by bzm:从文件读取base64的prompt提示词
    if (!StringUtils.isEmpty(this.user_prompt)) question.setText(this.user_prompt);
    question.setFont(new Font(question.getDisplay(), "Courier New", 12, SWT.NORMAL));

    answer = new Text(sashForm, SWT.MULTI | SWT.WRAP);
    gdAn = new GridData(GridData.FILL_HORIZONTAL);
    // gdAn.heightHint = 300;
    answer.setLayoutData(gdAn);
    answer.setText("生成内容:");
    answer.setFont(new Font(answer.getDisplay(), "Courier New", 12, SWT.NORMAL));

    Composite comp = new Composite(parent, SWT.NONE);
    comp.setLayout(new GridLayout(3, false));
    comp.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
    Button set = new Button(comp, SWT.PUSH);
    set.setText("生成内容");
    set.addListener(
        SWT.Selection,
        new Listener() {
          @Override
          public void handleEvent(Event event) {
            switch (genCombo.getSelectionIndex()) {
              case 0: // "指标-dws-ads"
                handleSetBtn("tol_agent_index");
                break;
              case 1: // "数据流-dws-ads"
                // handleSetBtn("tol_vannal");
                handleSetBtn("tol_agent_dws_ads");
                break;
              case 2: // "数据流-dwd"
                handleSetBtn("tol_agent_dwd");
                break;
              case 3: // "数据流-grafana"
                handleSetBtn("tol_agent_gra");
                break;
              case 4: // "数据流-dws"
                // handleSetBtn("tol_vannal");
                handleSetBtn("tol_agent_dws");
                break;
              case 5: // "数据流-ads"
                handleSetBtn("tol_agent_ads");
                break;
              case 6: // "API接口-sql"
                handleSetBtn("tol_agent_api_sql");
                break;
              case 7: // "C语言"
                handleSetBtn("tol_agent_c");
                break;
              case 8: // "API接口-python"
                handleSetBtn("tol_agent_api_python");
                break;
              case 9: // "生成规则"
                handleSetBtn("tol_agent_rules");
                break;
            }
          }
        });
    Button save = new Button(comp, SWT.PUSH);
    save.setText("生成到文件");
    save.addListener(
        SWT.Selection,
        new Listener() {
          @Override
          public void handleEvent(Event event) {
            switch (genCombo.getSelectionIndex()) {
              case 0: // "智能报表"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_report");
                }
                saveData(answer.getText());
                break;
              case 1: // "数据流-dws-ads"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_dws_ads");
                }
                saveData(answer.getText());
                break;
              case 2: // "数据流-dwd"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_dwd");
                }
                saveData(answer.getText());
                break;
              case 3: // "数据流-grafana"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_gra");
                }
                saveData(answer.getText());
                break;
              case 4: // "数据流-dws"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_dws");
                }
                saveData(answer.getText());
                break;
              case 5: // "数据流-ads"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_ads");
                }
                saveData(answer.getText());
                break;
              case 6: // "API接口-sql"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_api_sql");
                }
                saveData(answer.getText());
                break;
              case 7: // "c语言"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_c");
                }
                saveData(answer.getText());
                break;
              case 8: // "API接口-python"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_api_python");
                }
                saveData(answer.getText());
                break;
              case 9: // "生成规则"
                if (answer.getText().length() < 30) {
                  handleSetBtn("tol_agent_rules");
                }
                saveData(answer.getText());
                break;
            }
          }
        });
  }

  /** 处理生成的下拉框类型 */
  private void handleGenCombo() {
    // prompt的提示词需要从数据库读取
    String tmpStr = "";
    switch (genCombo.getSelectionIndex()) {
      case 0: // "智能报表"
        tmpStr =
            "根据dwd_dev_print_list表名称生dws和ads表.\n"
                + "1. 查询维度是 型号,版本\n"
                + "2. 统计指标是(一定要加单引号,不然会变成英文) '打印成功次数,打印成功率'\n"
                + "3. 条件是 print_id is not null";
        break;
      case 1: // "数据流-dws-ads"
        tmpStr =
            "1. 根据dwd_dev_d_code_dev表生成dws和ads表\n"
                + "2. ads和dws表名要加入 brand_code 的字母\n"
                + "3. 查询条件是前30天和前12月,并且print_id不为空\n"
                + "4. 统计的维度是按型号,版本,品牌,国家,错误码\n"
                + "5. 国家字段处理过程:replace(JSON_EXTRACT(getip(ip),'$.country'),'\"','') as country\n"
                + "6. 品牌字段处理过程: 通print_id字段关联dws_complete_brand_print_list表,获取的brand字段\n"
                + "7. sum汇总统计code_cnt";
        break;
      case 2: // "数据流-dwd"
        tmpStr =
            "根据 device_data.ods_cr_k1_device_event 表读取code='key706'的detail,生成dwd_temp_hum_xxxx开头的表.\n"
                + "detail的json例子:\n"
                + "{ error_code:xs2000,\n"
                + "  t1:{temp:T1盒子的温度,hum:T1盒子的湿度},\n"
                + "  t2:{temp:T2盒子的温度,hum:T2盒子的湿度},\n"
                + "  t3:{temp:T3盒子的温度,hum:T3盒子的湿度},\n"
                + "  t4:{temp:T4盒子的温度,hum:T4盒子的湿度},\n"
                + "  hot_bed_temp:200 ,\n"
                + "  hot_end_temp:200 ,\n"
                + "  chamber_temp:200 \n"
                + "}";
        break;
      case 3: // "数据流-grafana"
        tmpStr = "从ads_dev_print_feedback表生成柱状图.按型号和版本维度统计fd_type=0和fd_type=1个数";
        break;
      case 4: // "数据流-dws"
        tmpStr =
            "1. 根据dwd_dev_d_code_dev表生成dws表\n"
                + "2. dws表名要加入 brand_code 的字母\n"
                + "3. 查询条件是前30天和前12月,并且print_id不为空\n"
                + "4. 统计的维度是按型号,版本,品牌,国家,错误码\n"
                + "5. 国家字段处理过程:replace(JSON_EXTRACT(getip(ip),'$.country'),'\"','') as country\n"
                + "6. 品牌字段处理过程: 通print_id字段关联dws_complete_brand_print_list表,获取的brand字段\n"
                + "7. sum汇总统计code_cnt";
        break;
      case 5: // "数据流-ads"
        tmpStr =
            "1. 根据dws_dev_d_code_dev表生成ads表\n"
                + "2. ads_表名要加入 brand_code 的字母\n"
                + "3. 查询条件是前30天和前12月,并且print_id不为空\n"
                + "4. 统计的维度是按型号,版本,品牌,国家,错误码\n"
                + "5. 国家字段处理过程:replace(JSON_EXTRACT(getip(ip),'$.country'),'\"','') as country\n"
                + "6. 品牌字段处理过程: 通print_id字段关联dws_complete_brand_print_list表,获取的brand字段\n"
                + "7. sum汇总统计code_cnt";
        break;
      case 6: // "API接口-sql"
        tmpStr =
            "## description\n"
                + "根据dwd_dev_print_list表名称，查询条件是前30天和前12月，按型号和版本维度统计fd_type=0和fd_type=1个数\n"
                + "## returns\n"
                + "返回json对象,字段是'printer_model,version'\n"
                + "## in_params\n"
                + "printer_model:打印机型号,version:版本信息";
        break;
      case 7: // "c语言"
        tmpStr =
            "## 函数描述\n"
                + "根据输入参数log文件名称和offset偏移量,读取文件内容封装成json_object返回.\n"
                + "文件格式例子:\n"
                + "2025-06-15 14:35:26 FATAL test.c:100 this is a log test";
        break;
      case 8: // "API接口-python",
        tmpStr =
            "## description\n"
                + "计算result=a+b,并且打印result的值\n"
                + "## returns\n"
                + "返回json对象,字段是'result'\n"
                + "## in_params\n"
                + "a:int,b:int";
        break;
    }
    question.setText(tmpStr);
  }

  /** 根据生成的内容如hpl，wpl，python等，自动测试验证生成 */
  private void autoTestData(String txt) {}

  /** 把生成的内容保存到文件 */
  private void saveData(String txt) {
    // 获取当前日期时间
    LocalDateTime now = LocalDateTime.now();
    // 创建日期时间格式化对象，你可以根据需要调整模式
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
    // 使用格式化对象格式化当前日期时间
    String formattedDateTime = now.format(formatter);
    ExplorerPerspective.TreeItemFolder tif = ExplorerPerspective.getInstance().getSelData();
    if (tif == null) return;
    String dir = tif.path;
    JSONObject jsonObject;
    this.hpl = txt;
    String target_table = "";
    jsonObject = new JSONObject(txt);
    target_table = jsonObject.getString("target_table");
    String sql_120 = jsonObject.getString("sql_120");
    byte[] decodedBytes = Base64.getDecoder().decode(sql_120);
    // 将字节数组转换为字符串
    try {
      sql_120 = new String(decodedBytes, "UTF-8");
    } catch (UnsupportedEncodingException ignored) {

    }
    String sql_mem;
    boolean is_dispatch = true;
    String prjDir = System.getProperty("PROJECT_HOME");
    prjDir += "/llm/template/";
    int index = genCombo.getSelectionIndex();
    try {
      this.hwf = Files.readString(Path.of(prjDir + "ads_day.hwf"), StandardCharsets.UTF_8);
      switch (index) {
        case 0: // "智能报表"
          break;
        case 1: // "数据流-dws-ads"
          sql_mem = jsonObject.getString("sql_mem");
          this.hpl =
              Files.readString(Path.of(prjDir + "dws_ads_table.hpl"), StandardCharsets.UTF_8);
          this.hpl =
              this.hpl
                  .replace("{target_table}", target_table)
                  .replace("{sql_120}", sql_120)
                  .replace("{sql_mem}", sql_mem);
          break;
        case 2: // "数据流-dwd"
          this.hpl =
              Files.readString(Path.of(prjDir + "dwd_telemetry.hpl"), StandardCharsets.UTF_8);
          this.hpl = this.hpl.replace("{ods_cr_k1_device_event}", sql_120);
          this.hpl =
              this.hpl.replace(
                  "{ods_cr_k1_max_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_cr_k1_max_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f001_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f001_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f002_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f002_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f003_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f003_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f005_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f005_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f008_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f008_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f009_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f009_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f011_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f011_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f012_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f012_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f018_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f018_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f021_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f021_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f022_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f022_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f023_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f023_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f025_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f025_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f028_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f028_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_f030_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_f030_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_k1_se_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_k1_se_device_event"));
          this.hpl =
              this.hpl.replace(
                  "{ods_k1c_device_event}",
                  sql_120.replace("ods_cr_k1_device_event", "ods_k1c_device_event"));
          break;
        case 3: // "数据流-grafana"
          this.hpl = Files.readString(Path.of(prjDir + "gra_table.hpl"), StandardCharsets.UTF_8);
          this.hpl = this.hpl.replace("{target_table}", target_table).replace("{sql_gra}", sql_120);
          is_dispatch = false;
          break;
        case 4: // "数据流-dws"
          this.hpl = Files.readString(Path.of(prjDir + "dws_table.hpl"), StandardCharsets.UTF_8);
          this.hpl = this.hpl.replace("{target_table}", target_table).replace("{sql_120}", sql_120);
          break;
        case 5: // "数据流-ads"
          sql_mem = jsonObject.getString("sql_mem");
          this.hpl = Files.readString(Path.of(prjDir + "ads_table.hpl"), StandardCharsets.UTF_8);
          this.hpl =
              this.hpl
                  .replace("{target_table}", target_table)
                  .replace("{sql_120}", sql_120)
                  .replace("{sql_mem}", sql_mem);
          break;
        case 8:
        case 6: // "API接口"
          this.hpl = Files.readString(Path.of(prjDir + "api_info.hpl"), StandardCharsets.UTF_8);
          this.hpl =
              this.hpl
                  .replace("{target_table}", target_table)
                  .replace("{sql_120}", sql_120)
                  .replace("{func_desc}", jsonObject.getString("func_desc"))
                  .replace("{return_desc}", jsonObject.getString("return_desc"))
                  .replace("{in_params}", jsonObject.getString("in_params"))
                  .replace("{var_params}", jsonObject.getString("var_params"))
                  .replace("{out_params}", jsonObject.getString("out_params"));
          is_dispatch = false;
          break;
        case 7: // "c"
          this.hpl = Files.readString(Path.of(prjDir + "ReadLogData.c"), StandardCharsets.UTF_8);
          this.hpl =
              this.hpl
                  .replace("{description}", jsonObject.getString("description"))
                  .replace("{function}", sql_120);
          is_dispatch = false;
          break;
      }
      dir += "/" + target_table;
      dir = dir.replace("file://", "");
      System.out.println("dir=" + dir);
      Path dirPath = Paths.get(dir);
      if (!Files.exists(dirPath)) {
        System.out.println("dir=" + dir);
        Files.createDirectories(dirPath);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    MessageBox box = new MessageBox(shell);
    String hpl = dir + "/" + target_table;
    if (index == 7) {
      hpl += ".c";
    } else {
      hpl += ".hpl";
    }
    System.out.println("hpl=" + hpl);
    try (OutputStream outputStream = HopVfs.getOutputStream(hpl, false)) {
      outputStream.write(this.hpl.getBytes(StandardCharsets.UTF_8));
      outputStream.flush();
    } catch (Exception e) {
      box.setMessage(e.getMessage());
    }
    if (is_dispatch) {
      this.hwf = this.hwf.replace("{dir_hpl}", hpl).replace("{target_table}", target_table);
      String hwf = dir + "/" + target_table + ".hwf";
      try (OutputStream outputStream = HopVfs.getOutputStream(hwf, false)) {
        outputStream.write(this.hwf.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        box.setMessage("保存成功");
      } catch (Exception e) {
        box.setMessage(e.getMessage());
      }
    } else {
      box.setMessage("保存成功");
    }
    box.open();
    ExplorerPerspective.getInstance().refresh();
  }

  public static void main(String[] args) {
    String jsonStr =
        Const.llmdb_api(
            "tol_vannal",
            new String[] {
              "请完成 按机型统计该机型（月/周/日）的打印次数与激活总量的比例,\n" + "输出生成ads和dws表2个创建表的DDL和2个查询sql语句"
            });
    System.out.println("原始API返回: " + jsonStr); // 打印原始返回值

    // 检查是否是有效的JSON格式
    try {
      JSONObject jsonObj = new JSONObject(jsonStr);
      String targetTable = jsonObj.getString("target_table");
      String sqlContent = jsonObj.getString("sql");

      System.out.println("目标表: " + targetTable);
      System.out.println("SQL内容:\n" + sqlContent);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
